<html>
<head>
  <title>abrance</title>
  <basefont face="Consolas" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/602326 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: Consolas;
      font-size: 10pt;
    }
  </style>
</head>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/1.11.3/jquery.js"></script><script> $(function () {console.log($("a").attr("target", "_blank"));})</script>
<body>
<a name="3584"/>
<h1>mysql索引</h1>
<div>
<table bgcolor="#D4DDE5" border="0">
<tr><td><b>创建时间：</b></td><td><i>2020/11/12 16:32</i></td></tr>
<tr><td><b>更新时间：</b></td><td><i>2020/11/13 9:05</i></td></tr>
<tr><td><b>作者：</b></td><td><i>DaguguJ</i></td></tr>
<tr><td><b>标签：</b></td><td><i>db, mysql</i></td></tr>
</table>
</div>
<br/>

<div>
<span><div><h1 style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0.5em; color: rgb(64, 64, 64); font-weight: bold; text-rendering: optimizelegibility; font-size: 30px; word-break: break-word; font-family: -apple-system, BlinkMacSystemFont, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Segoe UI&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;"></h1><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 204px;"></col><col style="width: 950px;"></col></colgroup><tbody><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>索引</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 204px; padding: 8px;"><div><font color="#FFFFFF">聚簇索引与非聚簇索引（也叫二级索引）</font></div></td><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>数据库表的索引从<font style="color: rgb(255, 0, 0);">数据存储方式</font>上可以分为聚簇索引和非聚簇索引（又叫二级索引）两种</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>概念</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>聚簇索引：将数据存储与索引放到了一块，找到索引也就找到了数据</div></li><li><div>非聚簇索引：将数据存储于索引分开结构，索引结构的叶子节点指向了数据的对应行，myisam通过key_buffer把索引先缓存到内存中，当需要访问数据时（通过索引访问数据），在内存中直接搜索索引，然后通过索引找到磁盘相应数据，这也就是为什么索引不在key buffer命中时，速度慢的原因</div></li><li><div>澄清一个概念：innodb中，在聚簇索引之上创建的索引称之为辅助索引（除聚簇索引以外的都是辅助索引（innodb中）），辅助索引访问数据总是需要二次查找，非聚簇索引都是辅助索引，像复合索引、前缀索引、唯一索引，辅助索引叶子节点存储的不再是行的物理位置，而是主键值</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>区别</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>聚簇索引</div></li><ul><li><div>1. 索引必须为唯一索引</div></li><li><div>2. 叶子节点处储存的是整行数据（这也是为何用主键（聚簇索引）进行查询时，查询速度会较快的原因（减少回表查询））</div></li></ul><li><div>非聚簇索引</div></li><ul><li><div>1. 索引值必须为可不唯一</div></li><li><div>2. 叶子节点处储存的索引行跟主键（key+pk cols）     # 这可以判断是否会进行回表查询和覆盖索引</div></li></ul></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>聚簇索引的工作原理</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>聚簇索引具有唯一性</div></li><li><div>由于聚簇索引是将数据跟索引结构放到一块，因此一个表仅有一个聚簇索引</div></li><li><div>一个误区：把主键自动设为聚簇索引</div></li><li><div>聚簇索引默认是主键，如果表中没有定义主键，InnoDB 会选择一个唯一的非空索引代替。如果没有这样的索引，InnoDB 会隐式定义一个主键来作为聚簇索引。InnoDB 只聚集在同一个页面中的记录。包含相邻健值的页面可能相距甚远。如果你已经设置了主键为聚簇索引，必须先删除主键，然后添加我们想要的聚簇索引，最后恢复设置主键即可。</div></li><li><div>此时其他索引只能被定义为非聚簇索引。这个是最大的误区。有的主键还是无意义的自动增量字段，那样的话Clustered index对效率的帮助，完全被浪费了。</div></li><li><div>刚才说到了，聚簇索引性能最好而且具有唯一性，所以非常珍贵，必须慎重设置。一般要根据这个表最常用的SQL查询方式来进行选择，某个字段作为聚簇索引，或组合聚簇索引，这个要看实际情况。</div></li><li><div>记住我们的最终目的就是在相同结果集情况下，尽可能减少逻辑IO。</div></li><li><div><img src="mysql索引_files/Image.png" type="image/png" data-filename="Image.png"/></div></li><li><div><img src="mysql索引_files/Image [1].png" type="image/png" data-filename="Image.png" width="440"/></div></li><li><div><br/></div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>innodb和MyISAM</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>1. InnoDB使用的是聚簇索引，将主键组织到一棵B+树中，而行数据就储存在叶子节点上，若使用&quot;where id = 14&quot;这样的条件查找主键，则按照B+树的检索算法即可查找到对应的叶节点，之后获得行数据。</div></li><li><div>2. 若对Name列进行条件搜索，则需要两个步骤：第一步在辅助索引B+树中检索Name，到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作，最终到达叶子节点即可获取整行数据。（重点在于通过其他键需要建立辅助索引）</div></li><li><div>MyISM使用的是非聚簇索引，非聚簇索引的两棵B+树看上去没什么不同，节点的结构完全一致只是存储的内容不同而已，主键索引B+树的节点存储了主键，辅助键索引B+树存储了辅助键。表数据存储在独立的地方，这两颗B+树的叶子节点都使用一个地址指向真正的表数据，对于表数据来说，这两个键没有任何差别。由于索引树是独立的，通过辅助键检索无需访问主键的索引树。</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>聚簇索引的优势</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div><span style="font-size: unset; color: unset; font-family: unset;">看上去聚簇索引的效率明显要低于非聚簇索引，因为每次使用辅助索引检索都要经过两次B+树查找，这不是多此一举吗？聚簇索引的优势在哪？</span></div></li><li><div>1. 由于行数据和叶子节点存储在一起，同一页中会有多条行数据，访问同一数据页不同行记录时，已经把页加载到了Buffer中，再次访问的时候，会在内存中完成访问，不必访问磁盘。这样主键和行数据是一起被载入内存的，找到叶子节点就可以立刻将行数据返回了，如果按照主键Id来组织数据，获得数据更快。</div></li><li><div>2. 辅助索引使用主键作为&quot;指针&quot;而不是使用地址值作为指针的好处是，减少了当出现行移动或者数据页分裂时辅助索引的维护工作，使用主键值当作指针会让辅助索引占用更多的空间，换来的好处是InnoDB在移动行时无须更新辅助索引中的这个&quot;指针&quot;。也就是说行的位置（实现中通过16K的Page来定位）会随着数据库里数据的修改而发生变化（前面的B+树节点分裂以及Page的分裂），使用聚簇索引就可以保证不管这个主键B+树的节点如何变化，辅助索引树都不受影响。</div></li><li><div>3. 聚簇索引适合用在排序的场合，非聚簇索引不适合</div></li><li><div>4. 取出一定范围数据的时候，使用用聚簇索引</div></li><li><div>5. 二级索引需要两次索引查找，而不是一次才能取到数据，因为存储引擎第一次需要通过二级索引找到索引的叶子节点，从而找到数据的主键，然后在聚簇索引中用主键再次查找索引，再找到数据</div></li><li><div>6. 可以把相关数据保存在一起。例如实现电子邮箱时，可以根据用户 ID 来聚集数据，这样只需要从磁盘读取少数的数据页就能获取某个用户的全部邮件。如果没有使用聚簇索引，则每封邮件都可能导致一次磁盘 I/O。</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>聚簇索引的劣势</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div><span style="font-size: unset; color: unset; font-family: unset;">维护索引很昂贵，特别是插入新行或者主键被更新导至要分页(page split)的时候。建议在大量插入新行后，选在负载较低的时间段，通过OPTIMIZE TABLE优化表，因为必须被移动的行数据可能造成碎片。使用独享表空间可以弱化碎片</span></div></li><li><div>表如果使用UUId（随机ID）作为主键，使数据存储稀疏，这就会出现聚簇索引有可能有比全表扫面更慢，所以建议有序的主键，第一好插入，第二，磁盘顺序写快 </div></li><li><div>总结：</div></li><ul><li><div>B+树 插入节点时，会消耗大量资源</div></li><li><div>主键过长消耗空间</div></li></ul></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 204px; padding: 8px;"><div><font color="#FFFFFF">聚簇索引：为什么不建辅助索引在重复度高的列中</font></div></td><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>理论</div></li><ul><li><div>辅助索引存储了对主键，如果select字段不在非聚簇索引内，就需要跳到聚簇索引下（），再获取select字段值</div></li><li><div>如果辅助索引值重复率高，那么查询时就会大量出现 先查辅助索引表，在查聚簇索引表 的情况，导致整个流程很慢</div></li><li><div>如果where值重复率高的字段，select用了limit，只查较少数据，也就是跳的次数很少的情况下，还是可以建索引的（后来想想也没必要，limit限制了数量，全表扫描也很快，除非字段值是排序的，必须扫描完前面的所有值）</div></li><li><div>如果没有3这个前提，则不建议在值重复率高的字段上建索引，因为查询效率低，还需要维护索引</div></li></ul><li><div>实例</div></li><ul><li><div>一个字段使用拼音首字母做值，共有26种可能，加上索引后，百万加的数据量，使用索引的速度比不使用索引要慢</div></li></ul></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 204px; padding: 8px;"><div><font color="#FFFFFF">mysql 复合主键</font></div></td><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>概念</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>所谓的复合主键 就是指你表的主键含有一个以上的字段组成</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>形如</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>create table test</div></li><li><div>(</div></li><li><div>   name varchar(19),</div></li><li><div>   id number,</div></li><li><div>   value varchar(10),</div></li><li><div>   primary key (name,id)</div></li><li><div>)</div></li><li><div><br/></div></li><li><div>上面的name和id字段组合起来就是你test表的复合主键</div></li><li><div>它的出现是因为你的name字段可能会出现重名，所以要加上ID字段这样就可以保证你记录的唯一性</div></li><li><div>一般情况下，主键的字段长度和字段数目要越少越好</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>数据库分区和复合主键</div><div>问题</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>有一个表，想用分区的方式提升查询性能</div></li><ul><li><div>create table test</div></li><li><div>(</div></li><li><div>UID int auto_increment primary key,</div></li><li><div>Uname varchar(100),</div></li><li><div>department int</div></li><li><div>)</div></li><li><div>--其中department 的取值假设只有四个 1,2,3,4</div></li></ul><li><div>--那么这每个取值对应着一类科室，业务经常是针对一个科室的用户，所以按科室分区是理想的方式，如果按</div></li><li><div>--UID分区的话，一类业务在实现时，查询用户时要在多个分区中找，就体现不出分区的优势了</div></li><li><div>--问题：</div></li><li><div>--因为需要自增所以设置了主键，但是设置主键后，就不能仅以department建立分区，以下语句是无法执行的</div></li><ul><li><div>create table test</div></li><li><div>(</div></li><li><div>UID int auto_increment primary key,</div></li><li><div>Uname varchar(100),</div></li><li><div>department int</div></li><li><div>)</div></li><li><div>partition by key(department)</div></li><li><div>(</div></li><li><div>partition p1 values in(1),</div></li><li><div>partition p2 values in(2),</div></li><li><div>partition p3 values in(3),</div></li><li><div>partition p4 values in(4)</div></li><li><div>)</div></li></ul><li><div>--解决方案是：将ID,department设为复合主键</div></li><ul><li><div>create table test</div></li><li><div>(</div></li><li><div>UID int auto_increment primary key,</div></li><li><div>Uname varchar(100),</div></li><li><div>department int,</div></li><li><div>primary key(UID,department)</div></li><li><div>)</div></li><li><div>partition by key(department)</div></li><li><div>(</div></li><li><div>partition p1 values in(1),</div></li><li><div>partition p2 values in(2),</div></li><li><div>partition p3 values in(3),</div></li><li><div>partition p4 values in(4)</div></li><li><div>)</div></li></ul><li><div>--这样就实现了用户按照科别分区；理论上来讲提升了查询性能</div></li><li><div>--但是同时，使用了复合主键，又降低了性能</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 204px; padding: 8px;"><div><font color="#FFFFFF">mysql 最左前缀原则（联合索引使用规则）</font></div></td><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>参考链接</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div><a href="https://www.jianshu.com/p/9b3406bcb199">https://www.jianshu.com/p/9b3406bcb199</a></div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>假设数据 表 T (a,b,c) rowid 为物理位置</div></li><li><div>建立索引后相当于</div></li><ul><li><div>a b rowid</div></li><li><div>1 1 1</div></li><li><div>1 1 12</div></li><li><div>1 1 14</div></li><li><div>1 2 6</div></li><li><div>1 2 8</div></li><li><div>1 3 4</div></li><li><div>1 3 9</div></li><li><div>2 1 2</div></li><li><div>2 1 15</div></li><li><div>2 2 3</div></li><li><div>2 2 10</div></li><li><div>2 2 11</div></li><li><div>2 3 5</div></li><li><div>2 3 7</div></li><li><div>2 3 13</div></li></ul><li><div>当 select * from T where a = 1 and b = 3 的时候， 数据库系统可以直接从索引文件中直接二分法找到 A = 1 的记录，然后再 B = 3 的记录</div></li><li><div>但如果你 where b = 3 则需要遍历这个索引表的全部</div></li><li><div>mysql 建立多列索引（联合索引）有最左前缀的原则，即最左优先，如：</div></li><li><div>如果有一个 2 列的索引 (col1, col2)，则已经对 (col1)、(col1, col2) 上建立了索引；</div></li><li><div>如果有一个 3 列索引 (col1, col2, col3)，则已经对 (col1)、(col1, col2)、(col1, col2, col3) 上建立了索引</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>原理</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>b+ 树的数据项是复合的数据结构，比如 (name,age,sex) 的时候，b+ 树是按照从左到右的顺序来建立搜索树的，比如当 (张三,20,F) 这样的数据来检索的时候，b+ 树会优先比较 name 来确定下一步的所搜方向，如果 name 相同再依次比较 age 和 sex，最后得到检索的数据；但当 (20,F) 这样的没有 name 的数据来的时候，b+ 树就不知道第一步该查哪个节点，因为建立搜索树的时候 name 就是第一个比较因子，必须要先根据 name 来搜索才能知道下一步去哪里查询</div></li><li><div>比如当 (张三, F) 这样的数据来检索时，b+ 树可以用 name 来指定搜索方向，但下一个字段 age 的缺失，所以只能把名字等于张三的数据都找到，然后再匹配性别是 F 的数据了， 这个是非常重要的性质，即索引的最左匹配特性。（这种情况无法用到联合索引）</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>总结</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>联合索引，最左边的列享受索引优势，其它列效率越来越低，所以区分度高的列优先左边。</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>注意事项</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div><span style="color: unset; font-family: unset; font-size: unset;">1. 范围查询</span><br/></div></li><ul><li><div>mysql 会一直向右匹配直到遇到范围查询（&gt;、&lt;、between、like）就停止匹配。范围列可以用到索引，但是范围列后面的列无法用到索引。即，索引最多用于一个范围列，因此如果查询条件中有两个范围列则无法全用到索引</div></li></ul><li><div>2. like 语句的索引问题</div></li><ul><li><div>如果通配符 % 不出现在开头，则可以用到索引，但根据具体情况不同可能只会用其中一个前缀</div></li><li><div>在 like “value%” 可以使用索引，但是 like “%value%” 不会使用索引，走的是全表扫描</div></li></ul><li><div>3. 不要在列上进行运算</div></li><ul><li><div>如果查询条件中含有函数或表达式，将导致索引失效而进行全表扫描</div></li><li><div>例如 select * from user where YEAR(birthday) &lt; 1990</div></li><li><div>可以改造成 select * from users where birthday &lt;’1990-01-01′</div></li></ul><li><div>4. 索引不会包含有 NULL 值的列</div></li><ul><li><div>只要列中包含有 NULL 值都将不会被包含在索引中，复合索引中只要有一列含有 NULL 值，那么这一列对于此复合索引就是无效的。所以在数据库设计时不要让字段的默认值为 NULL</div></li></ul><li><div>5. 尽量选择区分度高的列作为索引，区分度的公式是 count(distinct col)/count(*)，表示字段不重复的比例，比例越大我们扫描的记录数越少，唯一键的区分度是 1，而一些状态、性别字段可能在大数据面前区分度就是 0。一般需要 join 的字段都要求区分度 0.1 以上，即平均 1 条扫描 10 条记录</div></li><li><div>6. 覆盖索引的好处</div></li><ul><li><div>如果一个索引包含所有需要的查询的字段的值，我们称之为覆盖索引。覆盖索引是非常有用的工具，能够极大的提高性能。因为，只需要读取索引，而无需读表，极大减少数据访问量</div></li></ul></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 204px; padding: 8px;"><div><font color="#FFFFFF">辅助索引和回表查询</font></div></td><td style="border: 1px solid rgb(0, 134, 36); background-color: rgb(0, 168, 45); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>概念</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>回表查询</div></li><ul><li><div>指使用辅助索引查到的是 聚簇索引的id，需要再查一次聚簇索引这个行为</div></li></ul></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>参考</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div><a href="https://learnku.com/articles/45521">https://learnku.com/articles/45521</a></div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div>use myTest;                 </div></li><li><div><br/></div></li><li><div>drop table if exists t1;</div></li><li><div><br/></div></li><li><div>CREATE TABLE `t1` (          </div></li><li><div>  `id` int(11) NOT NULL AUTO_INCREMENT,</div></li><li><div>  `a` int(20) DEFAULT NULL,</div></li><li><div>  `b` int(20) DEFAULT NULL,</div></li><li><div>  `c` int(20) DEFAULT NULL,</div></li><li><div>  `d` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,</div></li><li><div>  PRIMARY KEY (`id`),</div></li><li><div>  KEY `idx_a_b` (`a`,`b`),</div></li><li><div>  KEY `idx_c` (`c`)</div></li><li><div>) ENGINE=InnoDB CHARSET=utf8mb4 ;</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div>判断sql是否需要进行回表查询</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><ul><li><div><span style="color: unset; font-family: unset; font-size: unset;">回表查询是由于非聚簇索引的 B+Tree 叶子节点只记录了，PK cols 与 key。这就造成当查询字段非主键跟索引字段时，索引树无法直接提供所有数据列，从而要进行一次回表查询，也就是拿着主键 ID 再进行一次查询操作。</span><br/></div></li><li><div>例如 t1 表</div></li><li><div><br/></div></li><li><div>select * from t1 where c = 1; #sql_1</div></li><li><div>select id,c from t1 where c = 1; #sql_2，</div></li><li><div>当查询被非聚簇索引涵盖列时，则不需要走回表操作。即 sql_2 不需要走回表查询，sql_1 需要。</div></li></ul></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 204px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 950px; padding: 8px;"><div><br/></div></td></tr></tbody></table><h1 style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0.5em; text-rendering: optimizeLegibility; font-size: 30px; word-break: break-word; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br/></h1></div><div><br/></div></span>
</div></body></html> 